﻿using System;
using System.Collections.Generic;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace DeviceEntity.Tool
{
    /// <summary>
    /// 串口工具类
    /// </summary>
    class PortTool
    {
        /// <summary>
        /// 读取所有串口
        /// </summary>
        /// <returns></returns>
        public static string[] GetPorts()
        {
            try
            {
                return SerialPort.GetPortNames();
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
        /// <summary>
        /// 初始化并打开端口
        /// </summary>
        /// <param name="serialPort">串口对象</param>
        /// <param name="port">串口名</param>
        /// <param name="baudRate">波特率</param>
        public static void InitPort(SerialPort serialPort, string port, int baudRate)
        {
            try
            {
                lock (serialPort)
                {
                    if (serialPort.IsOpen == true)
                    {
                        serialPort.Close();
                    }
                    serialPort.PortName = port;
                    serialPort.BaudRate = baudRate;
                    serialPort.Parity = Parity.None;
                    serialPort.DataBits = 8;
                    serialPort.StopBits = StopBits.One;
                    serialPort.Open();
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
        /// <summary>
        /// 发送字符串
        /// </summary>
        /// <param name="port">串口对象</param>
        /// <param name="data">发送数据</param>
        /// <param name="sendWait">发送等待ms</param>
        public static async Task SendData(SerialPort port, string data, int sendWait = 0)
        {
            try
            {
                port.DiscardInBuffer();
                port.DiscardOutBuffer();
                await Task.Delay(sendWait);
                port.Write(data);
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
        /// <summary>
        /// 发送字节数组
        /// </summary>
        /// <param name="port">串口对象</param>
        /// <param name="data">发送数据</param>
        /// <param name="sendWait">发送等待ms</param>
        public static async Task SendData(SerialPort port, byte[] data, int sendWait = 0)
        {
            try
            {
                port.DiscardInBuffer();
                port.DiscardOutBuffer();
                await Task.Delay(sendWait);
                port.Write(data, 0, data.Length);
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
        /// <summary>
        /// 读取返回字符串
        /// </summary>
        /// <param name="port">串口</param>
        /// <param name="timeOut">返回超时ms</param>
        /// <param name="timeWait">返回等待ms</param>
        /// <returns>返回数据</returns>
        public static async Task<string> GetData(SerialPort port, int timeOut, int timeWait)
        {
            try
            {
                //返回值buffer
                byte[] buffer = new byte[] { };
                //返回等待
                if (timeWait != 0)
                {
                    await Task.Delay(timeWait);
                }
                //循环读取
                while (true)
                {
                    //缓存区字节>0 或 超时
                    if (port.BytesToRead > 0 || timeOut <= 0)
                    {
                        byte[] recData = new byte[port.BytesToRead];
                        if (port.BytesToRead > 0)
                        {
                            port.Read(recData, 0, recData.Length);
                            //存入返回值
                            buffer = buffer.Concat(recData).ToArray();
                        }
                        await Task.Delay(20);
                        timeOut -= 20;
                        //缓存区为空或者超时1S
                        if (port.BytesToRead == 0 || timeOut <= 0)
                            break;
                    }
                    await Task.Delay(20);
                    timeOut -= 20;
                }
                string reData = "";
                reData += Encoding.Default.GetString(buffer);
                return reData;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        /// <summary>
        /// 读取返回字节
        /// </summary>
        /// <param name="port">串口</param>
        /// <param name="timeOut">返回超时ms</param>
        /// <param name="timeWait">返回等待ms</param>
        /// <returns>返回数据</returns>
        public static async Task<byte[]> GetByteData(SerialPort port, int timeOut, int timeWait)
        {
            try
            {
                //返回值buffer
                byte[] buffer = new byte[] { };
                //返回等待
                if (timeWait != 0)
                {
                    await Task.Delay(timeWait);
                }
                //循环读取
                while (true)
                {
                    //缓存区字节>0 或 超时
                    if (port.BytesToRead > 0 || timeOut <= 0)
                    {
                        byte[] recData = new byte[port.BytesToRead];
                        if (port.BytesToRead > 0)
                        {
                            port.Read(recData, 0, recData.Length);
                            //存入返回值
                            buffer = buffer.Concat(recData).ToArray();
                        }
                        await Task.Delay(20);
                        timeOut -= 20;
                        //缓存区为空或者超时1S
                        if (port.BytesToRead == 0 || timeOut <= 0)
                            break;
                    }
                    await Task.Delay(20);
                    timeOut -= 20;
                }
                //未读取到数据
                if (buffer.Length == 0 && timeOut <= 0)
                {
                    buffer = null;
                }
                return buffer;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
    }
}
